local love = require "love"

local ASTEROID_BASE_SIDES = 8
local ASTEROID_BASE_VELOCITY = 30
local ASTEROID_DAMAGE_DEGREE = 0.3  -- 0~1

local Asteroid = {}

local function calculate_vertices(asteroid)
    asteroid.vertices = {}
    for i = 1, asteroid.sides do
        local angle = (i - 1) * (2 * math.pi / asteroid.sides) + asteroid.rotate_angle
        local x = asteroid.x + math.cos(angle) * asteroid.radius * asteroid.radius_ratios[i]
        local y = asteroid.y - math.sin(angle) * asteroid.radius * asteroid.radius_ratios[i]
        table.insert(asteroid.vertices, x)
        table.insert(asteroid.vertices, y)
    end
end

function Asteroid.new(self, ship_angle)
    local object = {}
    self.__index = self
    setmetatable(object, self)

    object.radius = math.random(30, 60)     -- hitbox

    local dice = math.random(4)
    if dice == 1 then
        object.x = math.random(object.radius, love.graphics.getWidth())
        object.y = -object.radius * 4
    elseif dice == 2 then
        object.x = -object.radius * 4
        object.y = math.random(object.radius, love.graphics.getHeight())
    elseif dice == 3 then
        object.x = math.random(object.radius, love.graphics.getWidth())
        object.y = love.graphics.getHeight() + object.radius * 4
    else
        object.x = love.graphics.getWidth() + object.radius * 4
        object.y = math.random(object.radius, love.graphics.getHeight())
    end

    object.sides = ASTEROID_BASE_SIDES
    object.velocity = ASTEROID_BASE_VELOCITY
    object.fly_angle = math.pi - ship_angle
    object.rotate_angle = 0
    object.radius_ratios = {}
    object.survive = object.sides

    for i = 1, object.sides do table.insert(object.radius_ratios, 1, math.random(8, 10) / 10) end

    calculate_vertices(object)

    return object
end

function Asteroid.damage(self, x, y)
    local closet_vertice = 1
    local distance = (self.vertices[2 * closet_vertice - 1] - x) ^ 2 + (self.vertices[2 * closet_vertice] - y) ^ 2
    for i = 2, self.sides do
        local new_distance = (self.vertices[2 * i - 1] - x) ^ 2 + (self.vertices[2 * i] - y) ^ 2
        if new_distance < distance then
            closet_vertice = i
            distance = new_distance
        end
    end

    -- lose a portion due to collision
    if closet_vertice == self.sides then
        self.radius_ratios[closet_vertice]     = ASTEROID_DAMAGE_DEGREE * self.radius_ratios[closet_vertice]
        self.radius_ratios[closet_vertice - 1] = ASTEROID_DAMAGE_DEGREE * 2 * self.radius_ratios[closet_vertice - 1]
        self.radius_ratios[1]                  = ASTEROID_DAMAGE_DEGREE * 2 * self.radius_ratios[1]
    elseif closet_vertice == 1 then
        self.radius_ratios[closet_vertice]     = ASTEROID_DAMAGE_DEGREE * self.radius_ratios[closet_vertice]
        self.radius_ratios[self.sides]         = ASTEROID_DAMAGE_DEGREE * 2 * self.radius_ratios[self.sides]
        self.radius_ratios[closet_vertice + 1] = ASTEROID_DAMAGE_DEGREE * 2 * self.radius_ratios[closet_vertice + 1]
    else
        self.radius_ratios[closet_vertice]     = ASTEROID_DAMAGE_DEGREE * self.radius_ratios[closet_vertice]
        self.radius_ratios[closet_vertice - 1] = ASTEROID_DAMAGE_DEGREE * 2 * self.radius_ratios[closet_vertice - 1]
        self.radius_ratios[closet_vertice + 1] = ASTEROID_DAMAGE_DEGREE * 2 * self.radius_ratios[closet_vertice + 1]
    end

    -- set radius_ratio to 0 if it is lower than 0.4
    for i = self.sides, 1, -1 do
        if self.radius_ratios[i] < 0.4 then
            table.remove(self.radius_ratios, i)
            table.remove(self.vertices, 2 * i - 1)
            table.remove(self.vertices, 2 * i)
            self.sides = self.sides - 1
            self.survive = self.survive - 1
        end
    end
    if self.sides < 3 then self.survive = 0 end
end

function Asteroid.collide(self, x, y, hitbox_radius)
    if math.sqrt((self.x - x) ^ 2 + (self.y - y) ^ 2) < self.radius + hitbox_radius then
        return true
    else
        return false
    end
end

function Asteroid.move(self)
    local dt = love.timer.getDelta()

    -- update the location
    self.x = self.x + math.cos(self.fly_angle) * self.velocity * dt
    self.y = self.y - math.sin(self.fly_angle) * self.velocity * dt

    -- rotate
    self.rotate_angle = self.rotate_angle + 1 / 6 * math.pi * dt

    -- recaclucate the vertices
    calculate_vertices(self)

    -- boundary limit
    if self.x + self.radius <= 0 then
        self.x = love.graphics.getWidth() + self.radius
    elseif self.x >= love.graphics.getWidth() + self.radius then
        self.x = - self.radius
    end

    if self.y + self.radius <= 0 then
        self.y = love.graphics.getHeight() + self.radius
    elseif self.y >= love.graphics.getHeight() + self.radius then
        self.y = - self.radius
    end

end

function Asteroid.draw(self)
    love.graphics.setColor(1, 1, 1)
    love.graphics.polygon("line", self.vertices)
end

return Asteroid
